/*
 *  Copright: 2008 Philipp Leitner, Distributed Systems Group,
 *            TU Wien, leitner@infosys.tuwien.ac.at
 *
 *  This file is part of DAIOS.
 *
 *  DAIOS is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation.
 * 
 *  DAIOS is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with DAIOS.  If not, see
 *  <http://www.gnu.org/licenses/>.
 * 
 */

package at.ac.tuwien.infosys.dsg.daios.util;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;

import org.apache.commons.collections.iterators.ArrayIterator;

import at.ac.tuwien.infosys.dsg.daios.exceptions.UnsupportedMessageTypeException;
import at.ac.tuwien.infosys.dsg.daios.framework.structs.DaiosMessage;
import at.ac.tuwien.infosys.dsg.daios.wsdl.AtomicTypesMapper;

/**
 * This is a special Daios encoder class. It implements
 * the logics to encode Daios messages as HTTP request
 * parameters.
 * 
 * @author philipp
 *
 */
public class RESTURLEncoder {
	
	/**
	 * Encode a Daios message as HTTP req	uest parameters.
	 * All fields of the message are appended to the URL
	 * in as HTTP GET parameters, i.e. in the format
	 * 'name=value'. This encoding supports only
	 * simple types. If the Daios message contains a
	 * complex field a
	 * <link>at.ac.tuwien.infosys.dsg.daios.exceptionsUnsupportedMessageTypeException</link>
	 * is being thrown.
	 * 
	 * @param url The base URL to append to.
	 * @param message The message to convert.
	 * @return The resulting URL, i.e. the base URL plus
	 * the converted message as HTTP parameters.
	 * @throws UnsupportedMessageTypeException
	 */
	public static URL encodeToURL(URL url, DaiosMessage message)
		throws UnsupportedMessageTypeException {
		
		URL newUrl = null;
		StringBuffer buffer = new StringBuffer(url.toExternalForm());
		
		// append the correct char separator for parameters
		if(url.toExternalForm().contains("\\?"))
			buffer.append("&");
		else
			buffer.append("?");
		
		// now add all message parts as "name"="value"
		// (all parts have to be simple types or arrays of such!)
		Enumeration<String> names = message.getNames();
		String s = null;
		while(names.hasMoreElements()) {
			s = names.nextElement();
			if(!message.isSimple(s))
				throw new UnsupportedMessageTypeException(
					"HTTP GET supports only simple message types.");
			append(s, message.get(s), buffer, message.isArray(s));
			if(names.hasMoreElements())
				buffer.append("&");
		}
		
		try {
			newUrl = new URL(buffer.toString());
		} catch (MalformedURLException e) {
			e.printStackTrace();
			return null;
		}
		return newUrl;
	}

	/**
	 * Append to the encoding buffer.
	 * 
	 * @param name The parameter name.
	 * @param value The parameter value.
	 * @param buffer The buffer to append to.
	 * @param isArray True if this value is an array, false otherwise.
	 */
	private static void append(String name, Object value,
			StringBuffer buffer, boolean isArray) {
		
		if(isArray)
			appendArray(name,value,buffer);
		else
			appendSingle(name,value,buffer);
		
		
	}

	/**
	 * Append a single value to the encoding buffer.
	 * 
	 * @param name The parameter name.
	 * @param value The parameter value.
	 * @param buffer The buffer to append to.
	 */	
	private static void appendSingle(String name, Object value,
			StringBuffer buffer) {
		
		buffer.append(EncodingHelper.getInstance().urlEncode(name));
		buffer.append("=");
		buffer.append(EncodingHelper.getInstance().urlEncode(
			AtomicTypesMapper.encodeForWire(value)));
		
	}
	
	/**
	 * Append an array value to the encoding buffer.
	 * 
	 * @param name The parameter name.
	 * @param value The parameter value.
	 * @param buffer The buffer to append to.
	 */	
	private static void appendArray(String name, Object value,
			StringBuffer buffer) {
		
		ArrayIterator it = new ArrayIterator(value);
		while(it.hasNext()) {
			appendSingle(name,it.next(),buffer);
			if(it.hasNext())
				buffer.append("&");
		
		}
	}
	
}
